github.com/zhongdalu/gf@v1.0.0/g/os/gfsnotify/gfsnotify_watcher_loop.go (about) 1 // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/zhongdalu/gf. 6 7 package gfsnotify 8 9 import ( 10 "github.com/zhongdalu/gf/g/container/glist" 11 ) 12 13 // 监听循环 14 func (w *Watcher) startWatchLoop() { 15 go func() { 16 for { 17 select { 18 // 关闭事件 19 case <-w.closeChan: 20 return 21 22 // 监听事件 23 case ev := <-w.watcher.Events: 24 //fmt.Println("ev:", ev.String()) 25 w.cache.SetIfNotExist(ev.String(), func() interface{} { 26 w.events.Push(&Event{ 27 event: ev, 28 Path: ev.Name, 29 Op: Op(ev.Op), 30 Watcher: w, 31 }) 32 return struct{}{} 33 }, REPEAT_EVENT_FILTER_INTERVAL) 34 35 case <-w.watcher.Errors: 36 //fmt.Fprintf(os.Stderr, "[gfsnotify] error: %s\n", err.Error()) 37 } 38 } 39 }() 40 } 41 42 // 获得文件路径的监听回调,包括层级的监听回调。 43 func (w *Watcher) getCallbacks(path string) (callbacks []*Callback) { 44 // 首先检索path对应的回调函数 45 if v := w.callbacks.Get(path); v != nil { 46 for _, v := range v.(*glist.List).FrontAll() { 47 callback := v.(*Callback) 48 callbacks = append(callbacks, callback) 49 } 50 } 51 // 其次查找父级目录有无回调注册 52 dirPath := fileDir(path) 53 if v := w.callbacks.Get(dirPath); v != nil { 54 for _, v := range v.(*glist.List).FrontAll() { 55 callback := v.(*Callback) 56 callbacks = append(callbacks, callback) 57 } 58 } 59 // 最后回溯查找递归回调函数 60 for { 61 parentDirPath := fileDir(dirPath) 62 if parentDirPath == dirPath { 63 break 64 } 65 if v := w.callbacks.Get(parentDirPath); v != nil { 66 for _, v := range v.(*glist.List).FrontAll() { 67 callback := v.(*Callback) 68 if callback.recursive { 69 callbacks = append(callbacks, callback) 70 } 71 } 72 } 73 dirPath = parentDirPath 74 } 75 return 76 } 77 78 // 事件循环(核心逻辑) 79 func (w *Watcher) startEventLoop() { 80 go func() { 81 for { 82 if v := w.events.Pop(); v != nil { 83 event := v.(*Event) 84 // 如果该路径一个回调也没有,那么没有必要执行后续逻辑,删除对该文件的监听 85 callbacks := w.getCallbacks(event.Path) 86 if len(callbacks) == 0 { 87 w.watcher.Remove(event.Path) 88 continue 89 } 90 switch { 91 // 如果是删除操作,那么需要判断是否文件真正不存在了,如果存在,那么将此事件认为“假删除” 92 case event.IsRemove(): 93 if fileExists(event.Path) { 94 // 底层重新添加监控(不用担心重复添加) 95 w.watcher.Add(event.Path) 96 // 修改事件操作为重命名(相当于重命名为自身名称,最终名称没变) 97 event.Op = RENAME 98 } 99 100 // 如果是重命名操作,那么需要判断是否文件真正不存在了,如果存在,那么将此事件认为“假命名” 101 // (特别是某些编辑器在编辑文件时会先对文件RENAME再CHMOD) 102 case event.IsRename(): 103 if fileExists(event.Path) { 104 // 底层有可能去掉了监控, 这里重新添加监控(不用担心重复添加) 105 w.watcher.Add(event.Path) 106 // 修改事件操作为修改属性 107 event.Op = CHMOD 108 } 109 110 // 创建文件/目录 111 case event.IsCreate(): 112 // ========================================= 113 // 注意这里只是添加底层监听,并没有注册任何的回调函数, 114 // 默认的回调函数为父级的递归回调 115 // ========================================= 116 if fileIsDir(event.Path) { 117 // 递归添加 118 for _, subPath := range fileAllDirs(event.Path) { 119 if fileIsDir(subPath) { 120 w.watcher.Add(subPath) 121 } 122 } 123 } else { 124 // 添加文件监听 125 w.watcher.Add(event.Path) 126 } 127 128 } 129 // 执行回调处理,异步处理 130 for _, v := range callbacks { 131 go func(callback *Callback) { 132 defer func() { 133 // 是否退出监控 134 if err := recover(); err != nil { 135 switch err { 136 case gFSNOTIFY_EVENT_EXIT: 137 w.RemoveCallback(callback.Id) 138 default: 139 panic(err) 140 } 141 } 142 }() 143 callback.Func(event) 144 }(v) 145 } 146 } else { 147 break 148 } 149 } 150 }() 151 }