2018-04-17 18:58:22 +08:00
|
|
|
|
// Copyright 2018 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
|
|
|
|
|
//
|
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
|
|
|
|
// You can obtain one at https://gitee.com/johng/gf.
|
|
|
|
|
|
|
|
|
|
// 文件监控.
|
|
|
|
|
package gfsnotify
|
|
|
|
|
|
|
|
|
|
import (
|
2018-11-05 16:26:08 +08:00
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
2019-01-01 19:43:31 +08:00
|
|
|
|
"gitee.com/johng/gf/g/container/glist"
|
2018-04-17 18:58:22 +08:00
|
|
|
|
"gitee.com/johng/gf/g/container/gmap"
|
2018-04-18 15:17:07 +08:00
|
|
|
|
"gitee.com/johng/gf/g/container/gqueue"
|
2018-11-05 10:39:18 +08:00
|
|
|
|
"gitee.com/johng/gf/g/container/gtype"
|
2018-11-03 17:50:00 +08:00
|
|
|
|
"gitee.com/johng/gf/g/os/gcache"
|
|
|
|
|
"gitee.com/johng/gf/third/github.com/fsnotify/fsnotify"
|
2018-04-17 18:58:22 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// 监听管理对象
|
|
|
|
|
type Watcher struct {
|
2018-11-17 02:39:23 +08:00
|
|
|
|
watcher *fsnotify.Watcher // 底层fsnotify对象
|
2018-11-16 18:20:09 +08:00
|
|
|
|
events *gqueue.Queue // 过滤后的事件通知,不会出现重复事件
|
|
|
|
|
cache *gcache.Cache // 缓存对象,主要用于事件重复过滤
|
2018-11-17 02:39:23 +08:00
|
|
|
|
callbacks *gmap.StringInterfaceMap // 注册的所有绝对路径(文件/目录)及其对应的回调函数列表map
|
2018-11-16 18:20:09 +08:00
|
|
|
|
closeChan chan struct{} // 关闭事件
|
2018-11-05 16:26:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 注册的监听回调方法
|
|
|
|
|
type Callback struct {
|
2018-11-17 02:39:23 +08:00
|
|
|
|
Id int // 唯一ID
|
|
|
|
|
Func func(event *Event) // 回调方法
|
|
|
|
|
Path string // 监听的文件/目录
|
2019-01-01 19:43:31 +08:00
|
|
|
|
elem *glist.Element // 指向回调函数链表中的元素项位置(便于删除)
|
2018-11-17 02:39:23 +08:00
|
|
|
|
recursive bool // 当目录时,是否递归监听(使用在子文件/目录回溯查找回调函数时)
|
2018-04-17 18:58:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 监听事件对象
|
|
|
|
|
type Event struct {
|
2018-11-05 16:26:08 +08:00
|
|
|
|
event fsnotify.Event // 底层事件对象
|
|
|
|
|
Path string // 文件绝对路径
|
|
|
|
|
Op Op // 触发监听的文件操作
|
|
|
|
|
Watcher *Watcher // 事件对应的监听对象
|
2018-04-17 18:58:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 按位进行识别的操作集合
|
|
|
|
|
type Op uint32
|
|
|
|
|
|
2018-11-03 17:50:00 +08:00
|
|
|
|
// 必须放到一个const分组里面
|
2018-04-17 18:58:22 +08:00
|
|
|
|
const (
|
|
|
|
|
CREATE Op = 1 << iota
|
|
|
|
|
WRITE
|
|
|
|
|
REMOVE
|
|
|
|
|
RENAME
|
|
|
|
|
CHMOD
|
|
|
|
|
)
|
|
|
|
|
|
2018-11-03 17:50:00 +08:00
|
|
|
|
const (
|
|
|
|
|
REPEAT_EVENT_FILTER_INTERVAL = 1 // (毫秒)重复事件过滤间隔
|
|
|
|
|
)
|
|
|
|
|
|
2018-11-05 10:34:28 +08:00
|
|
|
|
var (
|
2018-11-16 18:20:09 +08:00
|
|
|
|
// 默认的Watcher对象
|
2018-11-17 02:39:23 +08:00
|
|
|
|
defaultWatcher, _ = New()
|
2018-11-05 10:39:18 +08:00
|
|
|
|
// 默认的watchers是否初始化,使用时才创建
|
2018-11-17 02:39:23 +08:00
|
|
|
|
watcherInited = gtype.NewBool()
|
2018-11-05 16:26:08 +08:00
|
|
|
|
// 回调方法ID与对象指针的映射哈希表,用于根据ID快速查找回调对象
|
2018-11-17 02:39:23 +08:00
|
|
|
|
callbackIdMap = gmap.NewIntInterfaceMap()
|
2018-11-16 18:20:09 +08:00
|
|
|
|
// 回调函数的ID生成器(原子操作)
|
|
|
|
|
callbackIdGenerator = gtype.NewInt()
|
2018-11-05 10:34:28 +08:00
|
|
|
|
)
|
|
|
|
|
|
2018-11-03 17:50:00 +08:00
|
|
|
|
// 创建监听管理对象,主要注意的是创建监听对象会占用系统的inotify句柄数量,受到 fs.inotify.max_user_instances 的限制
|
2018-11-17 02:39:23 +08:00
|
|
|
|
func New() (*Watcher, error) {
|
2018-11-16 18:20:09 +08:00
|
|
|
|
w := &Watcher {
|
2018-11-17 02:39:23 +08:00
|
|
|
|
cache : gcache.New(),
|
|
|
|
|
events : gqueue.New(),
|
|
|
|
|
closeChan : make(chan struct{}),
|
|
|
|
|
callbacks : gmap.NewStringInterfaceMap(),
|
2018-11-16 18:20:09 +08:00
|
|
|
|
}
|
2018-11-17 02:39:23 +08:00
|
|
|
|
if watcher, err := fsnotify.NewWatcher(); err == nil {
|
|
|
|
|
w.watcher = watcher
|
|
|
|
|
} else {
|
|
|
|
|
return nil, err
|
2018-04-17 18:58:22 +08:00
|
|
|
|
}
|
2018-11-16 18:20:09 +08:00
|
|
|
|
w.startWatchLoop()
|
|
|
|
|
w.startEventLoop()
|
|
|
|
|
return w, nil
|
2018-04-17 18:58:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-11-17 02:39:23 +08:00
|
|
|
|
// 添加对指定文件/目录的监听,并给定回调函数;如果给定的是一个目录,默认非递归监控。
|
2018-11-05 16:26:08 +08:00
|
|
|
|
func Add(path string, callbackFunc func(event *Event), recursive...bool) (callback *Callback, err error) {
|
2018-11-17 02:39:23 +08:00
|
|
|
|
return defaultWatcher.Add(path, callbackFunc, recursive...)
|
2018-08-19 11:25:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 16:26:08 +08:00
|
|
|
|
// 递归移除对指定文件/目录的所有监听回调
|
2018-08-19 11:25:15 +08:00
|
|
|
|
func Remove(path string) error {
|
2018-11-17 02:39:23 +08:00
|
|
|
|
return defaultWatcher.Remove(path)
|
2018-08-19 11:25:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 16:26:08 +08:00
|
|
|
|
// 根据指定的回调函数ID,移出指定的inotify回调函数
|
|
|
|
|
func RemoveCallback(callbackId int) error {
|
|
|
|
|
callback := (*Callback)(nil)
|
|
|
|
|
if r := callbackIdMap.Get(callbackId); r != nil {
|
|
|
|
|
callback = r.(*Callback)
|
|
|
|
|
}
|
|
|
|
|
if callback == nil {
|
|
|
|
|
return errors.New(fmt.Sprintf(`callback for id %d not found`, callbackId))
|
|
|
|
|
}
|
2018-11-17 02:39:23 +08:00
|
|
|
|
defaultWatcher.RemoveCallback(callbackId)
|
|
|
|
|
return nil
|
2018-04-18 09:16:08 +08:00
|
|
|
|
}
|