github.com/zhongdalu/gf@v1.0.0/g/os/gfsnotify/gfsnotify.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 provides a platform-independent interface for file system notifications. 8 // 9 // 文件监控. 10 package gfsnotify 11 12 import ( 13 "errors" 14 "fmt" 15 16 "github.com/zhongdalu/gf/g/container/glist" 17 "github.com/zhongdalu/gf/g/container/gmap" 18 "github.com/zhongdalu/gf/g/container/gqueue" 19 "github.com/zhongdalu/gf/g/container/gtype" 20 "github.com/zhongdalu/gf/g/os/gcache" 21 "github.com/zhongdalu/gf/third/github.com/fsnotify/fsnotify" 22 ) 23 24 // 监听管理对象 25 type Watcher struct { 26 watcher *fsnotify.Watcher // 底层fsnotify对象 27 events *gqueue.Queue // 过滤后的事件通知,不会出现重复事件 28 cache *gcache.Cache // 缓存对象,主要用于事件重复过滤 29 callbacks *gmap.StrAnyMap // 注册的所有绝对路径(文件/目录)及其对应的回调函数列表map 30 closeChan chan struct{} // 关闭事件 31 } 32 33 // 注册的监听回调方法 34 type Callback struct { 35 Id int // 唯一ID 36 Func func(event *Event) // 回调方法 37 Path string // 监听的文件/目录 38 elem *glist.Element // 指向回调函数链表中的元素项位置(便于删除) 39 recursive bool // 当目录时,是否递归监听(使用在子文件/目录回溯查找回调函数时) 40 } 41 42 // 监听事件对象 43 type Event struct { 44 event fsnotify.Event // 底层事件对象 45 Path string // 文件绝对路径 46 Op Op // 触发监听的文件操作 47 Watcher *Watcher // 事件对应的监听对象 48 } 49 50 // 按位进行识别的操作集合 51 type Op uint32 52 53 // 必须放到一个const分组里面 54 const ( 55 CREATE Op = 1 << iota 56 WRITE 57 REMOVE 58 RENAME 59 CHMOD 60 ) 61 62 const ( 63 REPEAT_EVENT_FILTER_INTERVAL = 1 // (毫秒)重复事件过滤间隔 64 gFSNOTIFY_EVENT_EXIT = "exit" // 是否退出回调执行 65 ) 66 67 var ( 68 // 默认的Watcher对象 69 defaultWatcher, _ = New() 70 // 默认的watchers是否初始化,使用时才创建 71 watcherInited = gtype.NewBool() 72 // 回调方法ID与对象指针的映射哈希表,用于根据ID快速查找回调对象 73 callbackIdMap = gmap.NewIntAnyMap() 74 // 回调函数的ID生成器(原子操作) 75 callbackIdGenerator = gtype.NewInt() 76 ) 77 78 // 创建监听管理对象,主要注意的是创建监听对象会占用系统的inotify句柄数量,受到 fs.inotify.max_user_instances 的限制 79 func New() (*Watcher, error) { 80 w := &Watcher{ 81 cache: gcache.New(), 82 events: gqueue.New(), 83 closeChan: make(chan struct{}), 84 callbacks: gmap.NewStrAnyMap(), 85 } 86 if watcher, err := fsnotify.NewWatcher(); err == nil { 87 w.watcher = watcher 88 } else { 89 return nil, err 90 } 91 w.startWatchLoop() 92 w.startEventLoop() 93 return w, nil 94 } 95 96 // 添加对指定文件/目录的监听,并给定回调函数;如果给定的是一个目录,默认递归监控。 97 func Add(path string, callbackFunc func(event *Event), recursive ...bool) (callback *Callback, err error) { 98 return defaultWatcher.Add(path, callbackFunc, recursive...) 99 } 100 101 // 递归移除对指定文件/目录的所有监听回调 102 func Remove(path string) error { 103 return defaultWatcher.Remove(path) 104 } 105 106 // 根据指定的回调函数ID,移出指定的inotify回调函数 107 func RemoveCallback(callbackId int) error { 108 callback := (*Callback)(nil) 109 if r := callbackIdMap.Get(callbackId); r != nil { 110 callback = r.(*Callback) 111 } 112 if callback == nil { 113 return errors.New(fmt.Sprintf(`callback for id %d not found`, callbackId)) 114 } 115 defaultWatcher.RemoveCallback(callbackId) 116 return nil 117 } 118 119 // 在回调方法中调用该方法退出回调注册 120 func Exit() { 121 panic(gFSNOTIFY_EVENT_EXIT) 122 }